from decorator import decorator
from itertools import cycle
from utils import showTextDecorator
import random

class GameEnds(Exception):
    pass

from model import *
from manager import Manager
from gamemap import GameMap
import config

class Game:
    def __init__(self):
        pass

    def show(self,info):
        #pprint needed
        print info

    def showText(self,text):
        print text

    def getInput(self,check=None,prompt=None,errorMsg="Error"):
        if prompt is not None:
            print prompt

        while True:
            try:
                res=self.rawInput()
                if check is not None:
                    while not check(res):
                        self.error(errorMsg)
                        res=self.rawInput()
            except (TypeError,ValueError):
                self.error(errorMsg)
            else :
                return res

    def rawInput(self):
        return raw_input()


    @showTextDecorator
    def welcome(self,player):
        return "It is {}'s turn.".format(player)

    @showTextDecorator
    def goodbye(self,player):
        return "{}'s turn ends.".format(player)

    @showTextDecorator
    def win(self,player):
        return "{} wins.".format(player)

    def error(self,text):
        print text

    def showTable(self,table,title=None):
        if title:
            print title

        for row in table:
            print ' '.join(map(str,row))

    def choice(self,choiceList,returnCode=False,prompt=None,errorMsg=''):

        if prompt:
            self.showText(prompt)

        for num,choice in enumerate(choiceList):
            prompt,option = choice
            print "{} {}".format(num,prompt)

        code=int(
                self.getInput(
                    lambda x: not x or 0<=int(x)<=len(choiceList),
                    errorMsg=errorMsg,
                    ) or -1
                )

        if returnCode :
            return code
        else :
            return choiceList[code][1] if code!=-1 else code

class Monopoly(Game):
    def __init__(self,configFileName=None,mapFile=None):
        Game.__init__(self)

        self.manager=Manager(self,config.Config(configFileName))
        self.cardList=self.manager.config.cardList

        self.map_=GameMap(self.manager,mapFile)
        self.manager.setMap(self.map_)
        self.maxN=self.map_.maxN

        self.players=[]
        self.lost=[]
        self.date=self.manager.config.date.initDate
        self.roundTime=self.manager.config.date.roundTime
        self.endDate=self.manager.config.date.endDate

        manager=self.manager
        self.basicChoice=[
                ('View the map.',manager.viewMap),('View the initial map.',manager.viewInitMap),
                ('Use Item.',manager.item),('View a certain location.',manager.view),
                ('Show warning in next 10 steps.',manager.warning),('Show profile of players.',manager.profile),
                ('Toss.',manager.toss),('Admit failure',manager.lose),
                ]

        self.TOSS=self.manager.toss
        self.LOSE=self.manager.lose
        self.ended=False

    def start(self):
        self.showText("Welecome to MONOPOLY.")
        ps=self.getInput(
                prompt="Please input the number of players.",
                check=lambda x:1<int(x)<10,
                )
        ps=int(ps)

        for i in range(ps):
            name=self.getInput(
                    prompt="What be thy name, player bearing code {}".format(i),
                )

            self.regPlayer(name,i)

    def loop(self):
        try:
            for player in cycle(self.players+[None]):
                import pdb;pdb.set_trace()

                if player is None:
                    newDate=self.date+self.roundTime
                    if newDate.month!=self.date.month:
                        self.monthClear()

                    self.date=newDate

                    if self.date>=self.endDate:
                        self.end()

                        break

                    continue

                if player in self.lost:
                    continue

                self.welcome(player)
                self.showText(
                        "Visual Date: {}. Direction:{}. Cash:{}".format(
                            self.date,
                            'clockwise' if player.dir_>0 else 'otherclockwise',
                            player.cash,
                            ),
                        )

                choice=None
                while choice not in [self.TOSS,self.LOSE]:
                    choice=self.choice(
                            self.basicChoice,
                            prompt="=================================\nWhat is your command?",
                            errorMsg="Choice Invalid",
                            )

                    if choice != -1:
                        choice(player)
                   
                self.goodbye(player)
        except GameEnds:
            return

    def regPlayer(self,name,code):
        player=Player(self.manager,name,code,initCash=self.manager.config.data.initCash)
        self.players.append(player)

    def lose(self,player):
        self.lost.append(player)
        if len(self.lost)+1==len(self.players):
            self.end()

    def end(self):
        playerList=[player for player in self.players if player not in self.lost]
        playerList.sort(cmp=lambda x,y:cmp(x.inAll(),y.inAll()))
        winner=playerList[-1]

        self.win(winner)
        raise GameEnds

    def monthClear(self):
        self.manager.lotteryShow()
        self.manager.savingInterest()
